/*
 *************************************************************************
f * The contents of this file are subject to the Openbravo  Public  License
 * Version  1.1  (the  "License"),  being   the  Mozilla   Public  License
 * Version 1.1  with a permitted attribution clause; you may not  use this
 * file except in compliance with the License. You  may  obtain  a copy of
 * the License at http://www.openbravo.com/legal/license.html 
 * Software distributed under the License  is  distributed  on  an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific  language  governing  rights  and  limitations
 * under the License. 
 * The Original Code is Openbravo ERP. 
 * The Initial Developer of the Original Code is Openbravo SLU 
 * All portions are Copyright (C) 2001-2011 Openbravo SLU 
 * All Rights Reserved. 
 * Contributor(s):  ______________________________________.
 ************************************************************************
 */
package org.openbravo.furniture.ad_actionButton;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.hibernate.criterion.Restrictions;
import org.openbravo.advpaymentmngt.dao.AdvPaymentMngtDao;
import org.openbravo.advpaymentmngt.process.FIN_AddPayment;
import org.openbravo.advpaymentmngt.utility.FIN_Utility;
import org.openbravo.base.filter.IsIDFilter;
import org.openbravo.base.filter.RequestFilter;
import org.openbravo.base.filter.ValueListFilter;
import org.openbravo.base.secureApp.HttpSecureAppServlet;
import org.openbravo.base.secureApp.VariablesSecureApp;
import org.openbravo.dal.core.DalUtil;
import org.openbravo.dal.core.OBContext;
import org.openbravo.dal.service.OBCriteria;
import org.openbravo.dal.service.OBDal;
import org.openbravo.data.FieldProvider;
import org.openbravo.erpCommon.ad_forms.AcctServer;
import org.openbravo.erpCommon.utility.ComboTableData;
import org.openbravo.erpCommon.utility.DateTimeData;
import org.openbravo.erpCommon.utility.DimensionDisplayUtility;
import org.openbravo.erpCommon.utility.FieldProviderFactory;
import org.openbravo.erpCommon.utility.OBError;
import org.openbravo.erpCommon.utility.SequenceIdData;
import org.openbravo.erpCommon.utility.Utility;
import org.openbravo.model.common.businesspartner.BusinessPartner;
import org.openbravo.model.common.currency.Currency;
import org.openbravo.model.common.enterprise.Organization;
import org.openbravo.model.common.order.Order;
import org.openbravo.model.common.plm.Product;
import org.openbravo.model.financialmgmt.accounting.Costcenter;
import org.openbravo.model.financialmgmt.accounting.UserDimension1;
import org.openbravo.model.financialmgmt.accounting.UserDimension2;
import org.openbravo.model.financialmgmt.gl.GLItem;
import org.openbravo.model.financialmgmt.payment.FIN_FinancialAccount;
import org.openbravo.model.financialmgmt.payment.FIN_Payment;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentDetail;
import org.openbravo.model.financialmgmt.payment.FIN_PaymentScheduleDetail;
import org.openbravo.model.marketing.Campaign;
import org.openbravo.model.materialmgmt.cost.ABCActivity;
import org.openbravo.model.project.Project;
import org.openbravo.xmlEngine.XmlDocument;

public class AddOrderOrInvoiceFurniture extends HttpSecureAppServlet {
  private static final long serialVersionUID = 1L;
  private AdvPaymentMngtDao dao;
  private static final RequestFilter filterYesNo = new ValueListFilter("Y", "N", "");

  public void init(ServletConfig config) {
    super.init(config);
    boolHist = false;
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    log4j.debug("000000000000");
    VariablesSecureApp vars = new VariablesSecureApp(request);
    dao = new AdvPaymentMngtDao();

    if (vars.commandIn("DEFAULT")) {
      log4j.debug("0011");
      String strWindowId = vars.getGlobalVariable("inpwindowId",
          "AddOrderOrInvoiceFurniture|Window_ID");
      String strTabId = vars.getGlobalVariable("inpTabId", "AddOrderOrInvoiceFurniture|Tab_ID");
      // String strPaymentId = vars.getGlobalVariable("inpfinPaymentId", strWindowId + "|"
      // + "FIN_Payment_ID");
      String strOrderId = vars.getGlobalVariable("inpcOrderId", strWindowId + "|" + "C_Order_ID");
      // String strFinancialAccountId = vars.getStringParameter("inpfinFinancialAccountId");
	  String strFinancialAccountId = AddOrderOrInvoiceFurnitureData.selectDefaultFinAccount(this);
      //String strFinancialAccountId = "92B41D178D204EB78C03262C6D28CD6D";
      log4j.debug("111111111111");
      printPage(response, vars, strOrderId, strWindowId, strTabId, strFinancialAccountId);

    } else if (vars.commandIn("GRIDLIST")) {
      String strBusinessPartnerId = vars.getRequestGlobalVariable("inpBusinessPartnerId", "");
      if ("".equals(strBusinessPartnerId)) {
        strBusinessPartnerId = vars.getRequestGlobalVariable("inpcBPartnerId", "");
      }
      String strOrgId = vars.getRequestGlobalVariable("inpadOrgId", "");
      String strOrderId = vars.getRequestGlobalVariable("inpcOrderId", "");
      String strfinScheduledPaymentDetailId = AddOrderOrInvoiceFurnitureData
          .selectpaymentscheduleId(this, strOrderId);
      String strPaymentId = vars.getRequestGlobalVariable("inpfinPaymentId", "");
      String strExpectedDateFrom = vars.getStringParameter("inpExpectedDateFrom", "");
      String strExpectedDateTo = vars.getStringParameter("inpExpectedDateTo", "");
      String strDocumentType = vars.getStringParameter("inpDocumentType", "");
      String strSelectedPaymentDetails = vars.getInStringParameter("inpScheduledPaymentDetailId",
          "", null);
      boolean isReceipt = vars.getRequiredStringParameter("isReceipt").equals("Y");
      Boolean showAlternativePM = "Y".equals(vars.getStringParameter("inpAlternativePaymentMethod",
          filterYesNo));

      printGrid(response, vars, strBusinessPartnerId, strPaymentId, strOrgId, strExpectedDateFrom,
          strExpectedDateTo, strDocumentType, strSelectedPaymentDetails, isReceipt,
          showAlternativePM, strOrderId, strfinScheduledPaymentDetailId);
    } else if (vars.commandIn("BPARTNERBLOCK")) {
      boolean isReceipt = vars.getRequiredStringParameter("isReceipt").equals("Y");
      String strBusinessPartnerId = vars.getRequestGlobalVariable("inpBusinessPartnerId", "");
      if ("".equals(strBusinessPartnerId)) {
        strBusinessPartnerId = vars.getRequestGlobalVariable("inpcBPartnerId", "");
      }
      if (!"".equals(strBusinessPartnerId)) {
        BusinessPartner businessPartner = OBDal.getInstance().get(BusinessPartner.class,
            strBusinessPartnerId);
        if (FIN_Utility.isBlockedBusinessPartner(businessPartner.getId(), isReceipt, 4)) {
          businessPartnerBlocked(response, vars, businessPartner.getIdentifier());
        }
      } else {
        String strSelectedScheduledPaymentDetailIds = vars.getInStringParameter(
            "inpScheduledPaymentDetailId", "", null);
        if (!"".equals(strSelectedScheduledPaymentDetailIds)) {
          OBContext.setAdminMode(true);
          try {
            List<FIN_PaymentScheduleDetail> selectedPaymentDetails = FIN_Utility.getOBObjectList(
                FIN_PaymentScheduleDetail.class, strSelectedScheduledPaymentDetailIds);
            for (FIN_PaymentScheduleDetail psd : selectedPaymentDetails) {
              BusinessPartner bPartner;
              if (psd.getInvoicePaymentSchedule() == null) {
                bPartner = psd.getOrderPaymentSchedule().getOrder().getBusinessPartner();
              } else {
                bPartner = psd.getInvoicePaymentSchedule().getInvoice().getBusinessPartner();
              }
              if (FIN_Utility.isBlockedBusinessPartner(bPartner.getId(), isReceipt, 4)) {
                businessPartnerBlocked(response, vars, bPartner.getIdentifier());
              }
            }
          } finally {
            OBContext.restorePreviousMode();
          }
        }
      }
    } else if (vars.commandIn("SAVE") || vars.commandIn("SAVEANDPROCESS")) {
      boolean isReceipt = vars.getRequiredStringParameter("isReceipt").equals("Y");
      String strOrderId = vars.getRequestGlobalVariable("inpcOrderId", "");
      String strAction = null;
      String strPaymentId = "";
      if (vars.commandIn("SAVEANDPROCESS")) {
        // The default option is process
        strAction = (isReceipt ? "PRP" : "PPP");
      } else {
        strAction = vars.getRequiredStringParameter("inpActionDocument");
      }

      OBError myMessage = null;
      strAction = (isReceipt ? "PRP" : "PPP");
      Connection conn = null;
      try {
        conn = getTransactionConnection();
        AddOrderOrInvoiceFurnitureData[] lastorder = AddOrderOrInvoiceFurnitureData
            .selectlastorder2(this, strOrderId);
        strAction = (isReceipt ? "PRP" : "PPP");

        log4j.debug("neworderid: llegando");
        log4j.debug("neworderid: " + lastorder[0].cOrderId);

        strPaymentId = SequenceIdData.getUUID();
        log4j.debug("neworderid: " + lastorder[0].cOrderId);
        // Order objOrder = OBDal.getInstance().get(Order.class, neworderid);
        // String paymentdocno = Utility.getDocumentNo(this, vars.getClient(), "FIN_Payment", true);

        // String financialAccountId = CreateOrderFromProposal.selectfinancialaccount(this,
        // vars.getClient());
        //String financialAccountId = "92B41D178D204EB78C03262C6D28CD6D";
		String financialAccountId = AddOrderOrInvoiceFurnitureData.selectDefaultFinAccount(this);
		String doctype = AddOrderOrInvoiceFurnitureData.selectdefaultdoctype(this);
        //String doctype = "D132517AE775435B8EB2832CC61FCAB1";
        String paymentdocno = Utility.getDocumentNo(conn, this, vars,
            "E547CE89D4C04429B6340FFA44E70716", "FIN_Payment", "", doctype, false, true);
        log4j.debug("paymentdocno: " + paymentdocno);
        CreateOrderFromProposalData.insertpayment(conn, this, strPaymentId,
            lastorder[0].adClientId, lastorder[0].adOrgId, vars.getUser(),
            lastorder[0].cBpartnerId, lastorder[0].paymentmethod, paymentdocno, financialAccountId,
            doctype);

        releaseCommitConnection(conn);
      } catch (Exception e) {
        String strMessage = FIN_Utility.getExceptionMessage(e);
        try {
          releaseRollbackConnection(conn);
        } catch (Exception ignored) {
        }
        bdErrorGeneralPopUp(request, response, "Error", strMessage);
        OBDal.getInstance().rollbackAndClose();
        log4j.error("AddOrderOrInvoiceFurniture - SAVE AND PROCESS", e);
        return;
      }

      log4j.debug("paymentid:" + strPaymentId);

      // String strPaymentId = vars.getRequiredStringParameter("inpfinPaymentId");
      String strSelectedScheduledPaymentDetailIds = vars.getInStringParameter(
          "inpScheduledPaymentDetailId", "", null);
      String strAddedGLItems = vars.getStringParameter("inpGLItems");
      JSONArray addedGLITemsArray = null;
      try {
        addedGLITemsArray = new JSONArray(strAddedGLItems);
      } catch (JSONException e) {
        log4j.error("Error parsing received GLItems JSON Array: " + strAddedGLItems, e);
        bdErrorGeneralPopUp(request, response, "Error",
            "Error parsing received GLItems JSON Array: " + strAddedGLItems);
        return;
      }
      String strDifferenceAction = "";
      BigDecimal refundAmount = BigDecimal.ZERO;
      String strDifference = vars.getNumericParameter("inpDifference", "0");
      if (!"0".equals(strDifference)) {
        refundAmount = new BigDecimal(vars.getRequiredNumericParameter("inpDifference"));
        strDifferenceAction = vars.getStringParameter("inpDifferenceAction", "");
      }
      String strTabId = vars.getRequiredStringParameter("inpTabId");
      String strPaymentAmount = vars.getRequiredNumericParameter("inpActualPayment");
      String paymentCurrencyId = vars.getRequiredStringParameter("inpCurrencyId");
      BigDecimal exchangeRate = new BigDecimal("1");
      BigDecimal convertedAmount = new BigDecimal(strPaymentAmount);
      OBError message = null;
      // FIXME: added to access the FIN_PaymentSchedule and FIN_PaymentScheduleDetail tables to be
      // removed when new security implementation is done
      OBContext.setAdminMode();
      try {

        List<FIN_PaymentScheduleDetail> selectedPaymentDetails = FIN_Utility.getOBObjectList(
            FIN_PaymentScheduleDetail.class, strSelectedScheduledPaymentDetailIds);
        HashMap<String, BigDecimal> selectedPaymentDetailAmounts = getSelectedPaymentDetailsAndAmount(
            vars, strSelectedScheduledPaymentDetailIds);

        FIN_Payment payment = dao.getObject(FIN_Payment.class, strPaymentId);
        // Remove edited lines which are not in final selection and adjust outstanding amount for
        // documents
        removeNonSelectedDetails(payment, selectedPaymentDetails);
        BigDecimal newPaymentAmount = new BigDecimal(strPaymentAmount);
        if (newPaymentAmount.compareTo(payment.getAmount()) != 0) {
          payment.setAmount(newPaymentAmount);
          OBDal.getInstance().save(payment);
        }
        // load object in memory
        payment.getFINPaymentDetailList();
        if (addedGLITemsArray != null) {
          for (int i = 0; i < addedGLITemsArray.length(); i++) {
            JSONObject glItem = addedGLITemsArray.getJSONObject(i);
            BigDecimal glItemOutAmt = new BigDecimal(glItem.getString("glitemPaidOutAmt"));
            BigDecimal glItemInAmt = new BigDecimal(glItem.getString("glitemReceivedInAmt"));
            BigDecimal glItemAmt = BigDecimal.ZERO;
            if (isReceipt) {
              glItemAmt = glItemInAmt.subtract(glItemOutAmt);
            } else {
              glItemAmt = glItemOutAmt.subtract(glItemInAmt);
            }
            final String strGLItemId = glItem.getString("glitemId");
            checkID(strGLItemId);
            // Accounting Dimensions
            final String strElement_BP = glItem.getString("cBpartnerDim");
            checkID(strElement_BP);
            final BusinessPartner businessPartner = dao.getObject(BusinessPartner.class,
                strElement_BP);

            final String strElement_PR = glItem.getString("mProductDim");
            checkID(strElement_PR);
            final Product product = dao.getObject(Product.class, strElement_PR);

            final String strElement_PJ = glItem.getString("cProjectDim");
            checkID(strElement_PJ);
            final Project project = dao.getObject(Project.class, strElement_PJ);

            final String strElement_AY = glItem.getString("cActivityDim");
            checkID(strElement_AY);
            final ABCActivity activity = dao.getObject(ABCActivity.class, strElement_AY);

            final String strElement_CC = glItem.getString("cCostcenterDim");
            checkID(strElement_CC);
            final Costcenter costCenter = dao.getObject(Costcenter.class, strElement_CC);

            final String strElement_MC = glItem.getString("cCampaignDim");
            checkID(strElement_MC);
            final Campaign campaign = dao.getObject(Campaign.class, strElement_MC);

            final String strElement_U1 = glItem.getString("user1Dim");
            checkID(strElement_U1);
            final UserDimension1 user1 = dao.getObject(UserDimension1.class, strElement_U1);

            final String strElement_U2 = glItem.getString("user2Dim");
            checkID(strElement_U2);
            final UserDimension2 user2 = dao.getObject(UserDimension2.class, strElement_U2);

            FIN_AddPayment.saveGLItem(payment, glItemAmt, dao.getObject(GLItem.class, strGLItemId),
                businessPartner, product, project, campaign, activity, null, costCenter, user1,
                user2);
          }
        }
        FIN_AddPayment.setFinancialTransactionAmountAndRate(payment, exchangeRate, convertedAmount);
        payment = FIN_AddPayment.savePayment(payment, isReceipt, null, null, null, null, null,
            strPaymentAmount, null, null, null, selectedPaymentDetails,
            selectedPaymentDetailAmounts, strDifferenceAction.equals("writeoff"),
            strDifferenceAction.equals("refund"), dao.getObject(Currency.class, paymentCurrencyId),
            exchangeRate, convertedAmount);

        if (strAction.equals("PRP") || strAction.equals("PPP") || strAction.equals("PRD")
            || strAction.equals("PPW")) {
          try {
            // Process just in case there are lines, empty Refund payment does not need to call
            // process
            if (payment.getFINPaymentDetailList().size() > 0) {
              // If Action PRP o PPW, Process payment but as well create a financial transaction
              message = FIN_AddPayment.processPayment(vars, this,
                  (strAction.equals("PRP") || strAction.equals("PPP")) ? "P" : "D", payment);
            }
            if (strDifferenceAction.equals("refund")
                && !"Error".equalsIgnoreCase(message.getType())) {
              Boolean newPayment = !payment.getFINPaymentDetailList().isEmpty();
              FIN_Payment refundPayment = FIN_AddPayment.createRefundPayment(this, vars, payment,
                  refundAmount.negate(), exchangeRate);
              OBError auxMessage = FIN_AddPayment.processPayment(vars, this,
                  (strAction.equals("PRP") || strAction.equals("PPP")) ? "P" : "D", refundPayment);
              if (newPayment) {
                final String strNewRefundPaymentMessage = Utility.parseTranslation(this, vars,
                    vars.getLanguage(),
                    "@APRM_RefundPayment@" + ": " + refundPayment.getDocumentNo())
                    + ".";
                message.setMessage(strNewRefundPaymentMessage + " " + message.getMessage());
                if (payment.getGeneratedCredit().compareTo(BigDecimal.ZERO) != 0) {
                  payment.setDescription(payment.getDescription() + strNewRefundPaymentMessage
                      + "\n");
                  OBDal.getInstance().save(payment);
                  OBDal.getInstance().flush();
                }
              } else {
                message = auxMessage;
              }
            }
          } catch (Exception ex) {
            message = Utility.translateError(this, vars, vars.getLanguage(), ex.getMessage());
            log4j.error(ex);
            if (!message.isConnectionAvailable()) {
              bdErrorConnection(response);
              return;
            }
          }
        }
      } catch (Exception ex) {
        String strMessage = FIN_Utility.getExceptionMessage(ex);
        if (message != null && "Error".equals(message.getType())) {
          strMessage = message.getMessage();
        }
        bdErrorGeneralPopUp(request, response, "Error", strMessage);
        OBDal.getInstance().rollbackAndClose();
        log4j.error("AddOrderOrInvoiceFurniture - SAVE AND PROCESS", ex);
        return;

      } finally {
        OBContext.restorePreviousMode();
      }
      vars.setMessage(strTabId, message);
      printPageClosePopUpAndRefreshParent(response, vars);
    }

  }

  /*
   * Removes lines and schedule details which are not included in the given selected list
   */
  private void removeNonSelectedDetails(FIN_Payment payment,
      List<FIN_PaymentScheduleDetail> selectedPaymentDetails) {
    Set<String> toRemovePDs = new HashSet<String>();
    for (FIN_PaymentDetail pd : payment.getFINPaymentDetailList()) {
      for (FIN_PaymentScheduleDetail psd : pd.getFINPaymentScheduleDetailList()) {
        if (!selectedPaymentDetails.contains(psd)) {
          if (pd.getGLItem() != null) {
            toRemovePDs.add(pd.getId());
            continue;
          }
          // update outstanding amount
          List<FIN_PaymentScheduleDetail> outStandingPSDs = FIN_AddPayment.getOutstandingPSDs(psd);
          if (outStandingPSDs.size() == 0) {
            FIN_PaymentScheduleDetail newOutstanding = (FIN_PaymentScheduleDetail) DalUtil.copy(
                psd, false);
            newOutstanding.setPaymentDetails(null);
            newOutstanding.setWriteoffAmount(BigDecimal.ZERO);
            OBDal.getInstance().save(newOutstanding);
            toRemovePDs.add(pd.getId());
          } else {
            // First make sure outstanding amount is not equal zero
            if (outStandingPSDs.get(0).getAmount().add(psd.getAmount()).signum() == 0) {
              OBDal.getInstance().remove(outStandingPSDs.get(0));
            } else {
              // update existing PD with difference
              outStandingPSDs.get(0).setAmount(
                  outStandingPSDs.get(0).getAmount().add(psd.getAmount()));
              OBDal.getInstance().save(outStandingPSDs.get(0));
            }
            toRemovePDs.add(pd.getId());
          }
        }
      }
    }
    for (String pdID : toRemovePDs) {
      FIN_PaymentDetail pd = OBDal.getInstance().get(FIN_PaymentDetail.class, pdID);
      boolean hasPSD = pd.getFINPaymentScheduleDetailList().size() > 0;
      if (hasPSD) {
        FIN_PaymentScheduleDetail psd = OBDal.getInstance().get(FIN_PaymentScheduleDetail.class,
            pd.getFINPaymentScheduleDetailList().get(0).getId());
        pd.getFINPaymentScheduleDetailList().remove(psd);
        OBDal.getInstance().save(pd);
        OBDal.getInstance().remove(psd);
      }
      payment.getFINPaymentDetailList().remove(pd);
      OBDal.getInstance().save(payment);
      OBDal.getInstance().remove(pd);
      OBDal.getInstance().flush();
      OBDal.getInstance().refresh(payment);
    }
  }

  private void checkID(final String id) throws ServletException {
    if (!IsIDFilter.instance.accept(id)) {
      log4j.error("Input: " + id + " not accepted by filter: IsIDFilter");
      throw new ServletException("Input: " + id + " is not an accepted input");
    }
  }

  private void printPage(HttpServletResponse response, VariablesSecureApp vars, String strOrderId,
      String strWindowId, String strTabId, String strFinancialAccountId) throws IOException,
      ServletException {
    log4j.debug("Output: Add Payment button pressed on Make / Receipt Payment windows");
    log4j.debug("22222222222");
    // FIN_Payment payment = new AdvPaymentMngtDao().getObject(FIN_Payment.class, strPaymentId);
    Order objOrder = OBDal.getInstance().get(Order.class, strOrderId);
    String[] discard = { "discard" };
    if (objOrder.getBusinessPartner() != null) {
      discard[0] = "bpGridColumn";
    }
    log4j.debug("3333333333333");
    XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
        "org/openbravo/furniture/ad_actionButton/AddOrderOrInvoiceFurniture", discard)
        .createXmlDocument();
    log4j.debug("44444444444444444");

    xmlDocument.setParameter("directory", "var baseDirectory = \"" + strReplaceWith + "/\";\n");
    xmlDocument.setParameter("language", "defaultLang=\"" + vars.getLanguage() + "\";");
    xmlDocument.setParameter("theme", vars.getTheme());

    xmlDocument.setParameter("title",
        Utility.messageBD(this, "APRM_AddPaymentIn", vars.getLanguage()));

    xmlDocument.setParameter("dateDisplayFormat", vars.getSessionValue("#AD_SqlDateFormat"));
    log4j.debug("objOrder.getBusinessPartner(); " + objOrder.getBusinessPartner());
    if (objOrder.getBusinessPartner() != null) {
      xmlDocument.setParameter("businessPartner", objOrder.getBusinessPartner().getIdentifier());
      xmlDocument.setParameter("businessPartnerId", objOrder.getBusinessPartner().getId());
      xmlDocument.setParameter("credit", "");
      xmlDocument.setParameter("customerBalance", "0");
    } else {
      xmlDocument.setParameter("businessPartner", "");
      xmlDocument.setParameter("businessPartnerId", "");
      xmlDocument.setParameter("credit", "");
      xmlDocument.setParameter("customerBalance", "");

    }
    log4j.debug("55555555555");
    xmlDocument.setParameter("windowId", strWindowId);
    xmlDocument.setParameter("tabId", strTabId);
    xmlDocument.setParameter("orgId", objOrder.getOrganization().getId());
    xmlDocument.setParameter("orderId", objOrder.getId());
    xmlDocument.setParameter("paymentId", strOrderId);
    xmlDocument.setParameter("actualPayment", "0");
    xmlDocument.setParameter("headerAmount", "0");
    xmlDocument.setParameter("isReceipt", "Y");
    xmlDocument.setParameter("isSoTrx", "Y");
    /*
     * if (objOrder.getBusinessPartner() == null && (payment.getGeneratedCredit() == null ||
     * BigDecimal.ZERO.compareTo(payment .getGeneratedCredit()) != 0)) {
     * payment.setGeneratedCredit(BigDecimal.ZERO); OBDal.getInstance().save(objOrder);
     * OBDal.getInstance().flush(); }
     */
    xmlDocument.setParameter("generatedCredit", "0");
    log4j.debug("666666666666666");
    OBContext.setAdminMode(true);
    try {
      final Currency financialAccountCurrency = objOrder.getCurrency();
      if (financialAccountCurrency != null) {
        xmlDocument.setParameter("financialAccountCurrencyId", financialAccountCurrency.getId());
        xmlDocument.setParameter("financialAccountCurrencyName",
            financialAccountCurrency.getISOCode());
        xmlDocument.setParameter("financialAccountCurrencyPrecision", financialAccountCurrency
            .getStandardPrecision().toString());
      }
    } finally {
      OBContext.restorePreviousMode();
    }
    log4j.debug("7777777777777");
    xmlDocument.setParameter("exchangeRate", "");
    xmlDocument.setParameter("actualConverted", "");
    xmlDocument.setParameter("expectedConverted", "");
    xmlDocument.setParameter("currencyId", objOrder.getCurrency().getId());
    xmlDocument.setParameter("currencyName", objOrder.getCurrency().getISOCode());
    log4j.debug("888");

    boolean forcedFinancialAccountTransaction = false;
    // forcedFinancialAccountTransaction =
    // FIN_AddPayment.isForcedFinancialAccountTransaction(payment);
    // Action Regarding Document
    xmlDocument.setParameter("ActionDocument", "PRP");
    try {
      ComboTableData comboTableData = new ComboTableData(vars, this, "LIST", "",
          "F903F726B41A49D3860243101CEEBA25",
          forcedFinancialAccountTransaction ? "29010995FD39439D97A5C0CE8CE27D70" : "",
          Utility.getContext(this, vars, "#AccessibleOrgTree", "AddPaymentFromInvoice"),
          Utility.getContext(this, vars, "#User_Client", "AddPaymentFromInvoice"), 0);
      Utility.fillSQLParameters(this, vars, null, comboTableData, "AddOrderOrInvoiceFurniture", "");
      xmlDocument.setData("reportActionDocument", "liststructure", comboTableData.select(false));
      comboTableData = null;
    } catch (Exception ex) {
      throw new ServletException(ex);
    }
    log4j.debug("99999999999999");
    // Accounting Dimensions
    String doctype;
    doctype = AcctServer.DOCTYPE_ARReceipt;

    final String strCentrally = Utility.getContext(this, vars,
        DimensionDisplayUtility.IsAcctDimCentrally, strWindowId);
    final String strElement_BP = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_BPartner, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    final String strElement_PR = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_Product, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    final String strElement_PJ = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_Project, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    final String strElement_AY = Utility.getContext(this, vars, "$Element_AY", strWindowId);
    final String strElement_CC = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_CostCenter, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    final String strElement_MC = Utility.getContext(this, vars, "$Element_MC", strWindowId);
    final String strElement_U1 = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_User1, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    final String strElement_U2 = Utility.getContext(this, vars, DimensionDisplayUtility
        .displayAcctDimensions(strCentrally, DimensionDisplayUtility.DIM_User2, doctype,
            DimensionDisplayUtility.DIM_Header), strWindowId);
    xmlDocument.setParameter("strElement_BP", strElement_BP);
    xmlDocument.setParameter("strElement_PR", strElement_PR);
    xmlDocument.setParameter("strElement_PJ", strElement_PJ);
    xmlDocument.setParameter("strElement_AY", strElement_AY);
    xmlDocument.setParameter("strElement_CC", strElement_CC);
    xmlDocument.setParameter("strElement_MC", strElement_MC);
    xmlDocument.setParameter("strElement_U1", strElement_U1);
    xmlDocument.setParameter("strElement_U2", strElement_U2);
    log4j.debug("12112121212");

    // Add GL Items
    /*
     * JSONArray addedGLITemsArray = new JSONArray(); List<FIN_PaymentScheduleDetail>
     * gLItemScheduleDetailLines = FIN_AddPayment .getGLItemScheduleDetails(payment); for
     * (FIN_PaymentScheduleDetail psdGLItem : gLItemScheduleDetailLines) { try { JSONObject glItem =
     * new JSONObject(); glItem.put("glitemId", psdGLItem.getPaymentDetails().getGLItem().getId());
     * glItem.put("glitemDesc", psdGLItem.getPaymentDetails().getGLItem().getIdentifier());
     * glItem.put("finPaymentScheduleDetailId", psdGLItem.getId()); // Amounts if
     * (payment.isReceipt()) { glItem.put("glitemPaidOutAmt", psdGLItem.getAmount().signum() < 0 ?
     * psdGLItem.getAmount() .abs() : BigDecimal.ZERO); glItem.put("glitemReceivedInAmt",
     * psdGLItem.getAmount().signum() > 0 ? psdGLItem.getAmount() : BigDecimal.ZERO); } else {
     * glItem.put("glitemReceivedInAmt", psdGLItem.getAmount().signum() < 0 ? psdGLItem
     * .getAmount().abs() : BigDecimal.ZERO); glItem.put("glitemPaidOutAmt",
     * psdGLItem.getAmount().signum() > 0 ? psdGLItem.getAmount() : BigDecimal.ZERO); } //
     * Accounting Dimensions glItem.put("cBpartnerDim", psdGLItem.getBusinessPartner() != null ?
     * psdGLItem .getBusinessPartner().getId() : ""); glItem.put("cBpartnerDimDesc",
     * psdGLItem.getBusinessPartner() != null ? psdGLItem .getBusinessPartner().getIdentifier() :
     * ""); glItem.put("mProductDim", psdGLItem.getProduct() != null ?
     * psdGLItem.getProduct().getId() : ""); glItem.put("mProductDimDesc", psdGLItem.getProduct() !=
     * null ? psdGLItem.getProduct() .getIdentifier() : ""); glItem.put("cProjectDim",
     * psdGLItem.getProject() != null ? psdGLItem.getProject().getId() : "");
     * glItem.put("cProjectDimDesc", psdGLItem.getProject() != null ? psdGLItem.getProject()
     * .getIdentifier() : ""); glItem.put("cActivityDim", psdGLItem.getActivity() != null ?
     * psdGLItem.getActivity() .getId() : ""); glItem.put("cActivityDimDesc",
     * psdGLItem.getActivity() != null ? psdGLItem.getActivity() .getIdentifier() : "");
     * glItem.put("cCostcenterDim", psdGLItem.getCostCenter() != null ? psdGLItem.getCostCenter()
     * .getId() : ""); glItem.put("cCostcenterDimDesc", psdGLItem.getCostCenter() != null ?
     * psdGLItem .getCostCenter().getIdentifier() : ""); glItem.put("cCampaignDim",
     * psdGLItem.getSalesCampaign() != null ? psdGLItem .getSalesCampaign().getId() : "");
     * glItem.put("cCampaignDimDesc", psdGLItem.getSalesCampaign() != null ? psdGLItem
     * .getSalesCampaign().getIdentifier() : ""); glItem.put("user1Dim", psdGLItem.getStDimension()
     * != null ? psdGLItem.getStDimension() .getId() : ""); glItem.put("user1DimDesc",
     * psdGLItem.getStDimension() != null ? psdGLItem.getStDimension() .getIdentifier() : "");
     * glItem.put("user2Dim", psdGLItem.getNdDimension() != null ? psdGLItem.getNdDimension()
     * .getId() : ""); glItem.put("user2DimDesc", psdGLItem.getNdDimension() != null ?
     * psdGLItem.getNdDimension() .getIdentifier() : ""); // DisplayLogics
     * glItem.put("cBpartnerDimDisplayed", strElement_BP); glItem.put("mProductDimDisplayed",
     * strElement_PR); glItem.put("cProjectDimDisplayed", strElement_PJ);
     * glItem.put("cActivityDimDisplayed", strElement_AY); glItem.put("cCostcenterDimDisplayed",
     * strElement_CC); glItem.put("cCampaignDimDisplayed", strElement_MC);
     * glItem.put("user1DimDisplayed", strElement_U1); glItem.put("user2DimDisplayed",
     * strElement_U2); addedGLITemsArray.put(glItem); } catch (JSONException e) { log4j.error(e); }
     * }
     */
    xmlDocument.setParameter("glItems", "");
    // If UsedCredit is not equal zero, check Use available credit
    xmlDocument.setParameter("useCredit", "N");
    log4j.debug("2323232323");

    // Not allow to change exchange rate and amount
    final String strNotAllowExchange = Utility.getContext(this, vars, "NotAllowChangeExchange",
        strWindowId);
    xmlDocument.setParameter("strNotAllowExchange", strNotAllowExchange);
    log4j.debug("909090");
    dao = new AdvPaymentMngtDao();
    FIN_FinancialAccount financialAccount = dao.getObject(FIN_FinancialAccount.class,
        strFinancialAccountId);

    if (financialAccount.getWriteofflimit() != null) {
      final String strtypewriteoff;
      final String strAmountwriteoff;

      strtypewriteoff = financialAccount.getTypewriteoff();
      strAmountwriteoff = financialAccount.getWriteofflimit().toString();
      xmlDocument.setParameter("strtypewriteoff", strtypewriteoff);
      xmlDocument.setParameter("strAmountwriteoff", strAmountwriteoff);

      // Not allow to write off
      final String strWriteOffLimit = Utility.getContext(this, vars, "WriteOffLimitPreference",
          strWindowId);
      xmlDocument.setParameter("strWriteOffLimit", strWriteOffLimit);
    }
    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println(xmlDocument.print());
    out.close();
  }

  private void printGrid(HttpServletResponse response, VariablesSecureApp vars,
      String strBusinessPartnerId, String strPaymentId, String strOrgId,
      String strExpectedDateFrom, String strExpectedDateTo, String strDocumentType,
      String strSelectedPaymentDetails, boolean isReceipt, boolean showAlternativePM,
      String strOrderId, String strfinScheduledPaymentDetailId) throws IOException,
      ServletException {

    strDocumentType = "O";
    Order objOrder = OBDal.getInstance().get(Order.class, strOrderId);

    log4j.debug("Output: Grid with pending payments");
    dao = new AdvPaymentMngtDao();
    String[] discard = { "" };
    if (!"".equals(vars.getRequestGlobalVariable("inpBusinessPartnerId", ""))) {
      discard[0] = "businessPartnerName";
    }

    XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
        "org/openbravo/furniture/ad_actionButton/AddPaymentGridFurniture", discard)
        .createXmlDocument();

    // FIN_Payment payment = dao.getObject(FIN_Payment.class, strPaymentId);

    List<FIN_PaymentScheduleDetail> storedScheduledPaymentDetails = new ArrayList<FIN_PaymentScheduleDetail>();
    // This is to identify first load of the grid
    String strFirstLoad = vars.getStringParameter("isFirstLoad");
    /*
     * if (payment.getFINPaymentDetailList().size() > 0) { // Add payment schedule details related
     * to orders or invoices to storedSchedulePaymentDetails OBContext.setAdminMode(); try {
     * OBCriteria<FIN_PaymentScheduleDetail> obc = OBDal.getInstance().createCriteria(
     * FIN_PaymentScheduleDetail.class);
     * obc.add(Restrictions.in(FIN_PaymentScheduleDetail.PROPERTY_PAYMENTDETAILS,
     * payment.getFINPaymentDetailList())); obc.add(Restrictions.or(
     * Restrictions.isNotNull(FIN_PaymentScheduleDetail.PROPERTY_INVOICEPAYMENTSCHEDULE),
     * Restrictions.isNotNull(FIN_PaymentScheduleDetail.PROPERTY_ORDERPAYMENTSCHEDULE)));
     * storedScheduledPaymentDetails = obc.list(); } finally { OBContext.restorePreviousMode(); } }
     */
    // Pending Payments from invoice
    final List<FIN_PaymentScheduleDetail> selectedScheduledPaymentDetails = FIN_AddPayment
        .getSelectedPaymentDetails(
            "true".equals(strFirstLoad) ? new ArrayList<FIN_PaymentScheduleDetail>(
                storedScheduledPaymentDetails) : null, strSelectedPaymentDetails);
    // filtered scheduled payments list
    final List<FIN_PaymentScheduleDetail> filteredScheduledPaymentDetails = dao
        .getFilteredScheduledPaymentDetails(dao.getObject(Organization.class, strOrgId),
            dao.getObject(BusinessPartner.class, strBusinessPartnerId), objOrder.getCurrency(),
            null, null, FIN_Utility.getDate(strExpectedDateFrom),
            FIN_Utility.getDate(DateTimeData.nDaysAfter(this, strExpectedDateTo, "1")), null, null,
            strDocumentType, "", showAlternativePM ? null : objOrder.getPaymentMethod(),
            selectedScheduledPaymentDetails, isReceipt);
    // Remove related outstanding schedule details related to those ones being edited as amount will
    // be later added to storedScheduledPaymentDetails
    for (FIN_PaymentScheduleDetail psd : storedScheduledPaymentDetails) {
      filteredScheduledPaymentDetails.removeAll(FIN_AddPayment.getOutstandingPSDs(psd));
    }
    // Get stored not selected PSDs
    List<FIN_PaymentScheduleDetail> storedNotSelectedPSDs = new ArrayList<FIN_PaymentScheduleDetail>(
        storedScheduledPaymentDetails);
    storedNotSelectedPSDs.removeAll(selectedScheduledPaymentDetails);
    // Add stored but not selected details which maps documenttype
    filteredScheduledPaymentDetails.addAll(filterDocumenttype(storedNotSelectedPSDs,
        strDocumentType));

    FieldProvider[] data = FIN_AddPayment.getShownScheduledPaymentDetails(vars,
        selectedScheduledPaymentDetails, filteredScheduledPaymentDetails, false, null,
        strSelectedPaymentDetails);
    for (FIN_PaymentScheduleDetail psd : storedScheduledPaymentDetails) {
      // Calculate pending amount
      BigDecimal outstandingAmount = BigDecimal.ZERO;
      List<FIN_PaymentScheduleDetail> outStandingPSDs = FIN_AddPayment.getOutstandingPSDs(psd);
      if (outStandingPSDs.size() != 0) {
        for (FIN_PaymentScheduleDetail outPSD : outStandingPSDs) {
          outstandingAmount = outstandingAmount.add(outPSD.getAmount());
        }
      }
      for (int i = 0; i < data.length; i++) {
        if (data[i].getField("finScheduledPaymentDetailId").equals(psd.getId())) {
          FieldProviderFactory.setField(data[i], "outstandingAmount",
              psd.getAmount().add(outstandingAmount).toPlainString());
          if ("true".equals(strFirstLoad)) {
            FieldProviderFactory.setField(data[i], "difference", outstandingAmount.toPlainString());
            FieldProviderFactory
                .setField(data[i], "paymentAmount", psd.getAmount().toPlainString());
          }
        }
      }
    }

    data = groupPerDocumentType(data, strDocumentType, strfinScheduledPaymentDetailId);
    xmlDocument.setData("structure", (data == null) ? set() : data);

    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();
    out.println(xmlDocument.print());
    out.close();
  }

  private FieldProvider[] set() throws ServletException {
    HashMap<String, String> empty = new HashMap<String, String>();
    empty.put("finScheduledPaymentId", "");
    empty.put("salesOrderNr", "");
    empty.put("salesInvoiceNr", "");
    empty.put("expectedDate", "");
    empty.put("invoicedAmount", "");
    empty.put("expectedAmount", "");
    empty.put("paymentAmount", "");
    ArrayList<HashMap<String, String>> result = new ArrayList<HashMap<String, String>>();
    result.add(empty);
    return FieldProviderFactory.getFieldProviderArray(result);
  }

  private FieldProvider[] groupPerDocumentType(FieldProvider[] data, String strDocumenType,
      String strfinScheduledPaymentDetailId) {
    ArrayList<FieldProvider> gridLines = new ArrayList<FieldProvider>();
    HashMap<String, Integer> amountsPerGroupingField = new HashMap<String, Integer>();
    String groupingField = "finScheduledPaymentDetailId";
    if ("I".equals(strDocumenType)) {
      groupingField = "invoicePaymentScheduleId";
    } else if ("O".equals(strDocumenType)) {
      groupingField = "orderPaymentScheduleId";
    }

    for (int i = 0; i < data.length; i++) {
      log4j.debug("data[i].getField(finScheduledPaymentDetailId): "
          + data[i].getField("finScheduledPaymentDetailId"));
      log4j.debug("strfinScheduledPaymentDetailId: " + strfinScheduledPaymentDetailId);
      if (!amountsPerGroupingField.containsKey(data[i].getField(groupingField))
          || "".equals(data[i].getField(groupingField))) {
        if (data[i].getField("finScheduledPaymentDetailId").equals(strfinScheduledPaymentDetailId)) {
          amountsPerGroupingField.put(data[i].getField(groupingField), gridLines.size());
          FieldProviderFactory.setField(data[i], "rownum", String.valueOf(gridLines.size()));
          gridLines.add(data[i]);
        }
      } else {
        Integer listIndex = amountsPerGroupingField.get(data[i].getField(groupingField));
        FieldProvider row = gridLines.get(listIndex);
        FieldProviderFactory.setField(
            row,
            "finScheduledPaymentDetailId",
            row.getField("finScheduledPaymentDetailId") + ","
                + data[i].getField("finScheduledPaymentDetailId"));
        FieldProviderFactory.setField(
            row,
            "finSelectedPaymentDetailId",
            row.getField("finSelectedPaymentDetailId") + ","
                + data[i].getField("finScheduledPaymentDetailId"));
        FieldProviderFactory.setField(
            row,
            "outstandingAmount",
            new BigDecimal(row.getField("outstandingAmount")).add(
                new BigDecimal(data[i].getField("outstandingAmount"))).toString());
        BigDecimal payAmount = BigDecimal.ZERO;
        if (!"".equals(row.getField("paymentAmount"))) {
          payAmount = new BigDecimal(row.getField("paymentAmount"));
        }
        FieldProviderFactory.setField(
            row,
            "paymentAmount",
            !"".equals(data[i].getField("paymentAmount")) ? payAmount.add(
                new BigDecimal(data[i].getField("paymentAmount"))).toString() : (payAmount
                .compareTo(BigDecimal.ZERO) == 0 ? "" : payAmount.toString()));
        if ("O".equals(strDocumenType)) {
          String strGroupedInvoicesNr = row.getField("invoiceNr");
          FieldProviderFactory.setField(row, "invoiceNr", (strGroupedInvoicesNr.isEmpty() ? ""
              : strGroupedInvoicesNr + ", ") + data[i].getField("invoiceNr"));
          String invoiceNumber = row.getField("invoiceNr");
          String invoiceNumberTrunc = (invoiceNumber.length() > 17) ? invoiceNumber
              .substring(0, 14).concat("...").toString() : invoiceNumber;
          FieldProviderFactory.setField(row, "invoiceNrTrunc", invoiceNumberTrunc);
        } else if ("I".equals(strDocumenType)) {
          String strGroupedOrdersNr = row.getField("orderNr");
          FieldProviderFactory.setField(row, "orderNr", (strGroupedOrdersNr.isEmpty() ? ""
              : strGroupedOrdersNr + ", ") + data[i].getField("orderNr"));
          String orderNumber = row.getField("orderNr");
          String orderNumberTrunc = (orderNumber.length() > 17) ? orderNumber.substring(0, 14)
              .concat("...").toString() : orderNumber;
          FieldProviderFactory.setField(row, "orderNrTrunc", orderNumberTrunc);
        }
      }
    }
    FieldProvider[] result = new FieldProvider[gridLines.size()];
    gridLines.toArray(result);
    return result;
  }

  /**
   * Creates a HashMap with the FIN_PaymentScheduleDetail id's and the amount gotten from the
   * Session.
   * 
   * The amounts are stored in Session like "inpPaymentAmount"+paymentScheduleDetail.Id
   * 
   * @param vars
   *          VariablseSecureApp with the session data.
   * @param selectedPaymentScheduleDetails
   *          List of FIN_PaymentScheduleDetails that need to be included in the HashMap.
   * @return A HashMap mapping the FIN_PaymentScheduleDetail's Id with the corresponding amount.
   */
  private HashMap<String, BigDecimal> getSelectedPaymentDetailsAndAmount(VariablesSecureApp vars,
      String _strSelectedScheduledPaymentDetailIds) throws ServletException {
    String strSelectedScheduledPaymentDetailIds = _strSelectedScheduledPaymentDetailIds;
    // Remove "(" ")"
    strSelectedScheduledPaymentDetailIds = strSelectedScheduledPaymentDetailIds.replace("(", "");
    strSelectedScheduledPaymentDetailIds = strSelectedScheduledPaymentDetailIds.replace(")", "");
    HashMap<String, BigDecimal> selectedPaymentScheduleDetailsAmounts = new HashMap<String, BigDecimal>();
    // As selected items may contain records with multiple IDs we as well need the records list as
    // amounts are related to records
    StringTokenizer records = new StringTokenizer(strSelectedScheduledPaymentDetailIds, "'");
    Set<String> recordSet = new LinkedHashSet<String>();
    while (records.hasMoreTokens()) {
      recordSet.add(records.nextToken());
    }
    for (String record : recordSet) {
      if (", ".equals(record)) {
        continue;
      }
      Set<String> psdSet = new LinkedHashSet<String>();
      StringTokenizer psds = new StringTokenizer(record, ",");
      while (psds.hasMoreTokens()) {
        psdSet.add(psds.nextToken());
      }
      BigDecimal recordAmount = new BigDecimal(vars.getNumericParameter(
          "inpPaymentAmount" + record, ""));
      HashMap<String, BigDecimal> recordsAmounts = calculateAmounts(recordAmount, psdSet);
      selectedPaymentScheduleDetailsAmounts.putAll(recordsAmounts);
    }
    return selectedPaymentScheduleDetailsAmounts;
  }

  /**
   * This method returns a HashMap with pairs of UUID of payment schedule details and amounts
   * related to those ones.
   * 
   * @param recordAmount
   *          : amount to split among the set
   * @param psdSet
   *          : set of payment schedule details where to allocate the amount
   * @return
   */
  private HashMap<String, BigDecimal> calculateAmounts(BigDecimal recordAmount, Set<String> psdSet) {
    BigDecimal remainingAmount = recordAmount;
    HashMap<String, BigDecimal> recordsAmounts = new HashMap<String, BigDecimal>();
    // PSD needs to be properly ordered to ensure negative amounts are processed first
    List<FIN_PaymentScheduleDetail> psds = getOrderedPaymentScheduleDetails(psdSet);
    BigDecimal outstandingAmount = BigDecimal.ZERO;
    for (FIN_PaymentScheduleDetail paymentScheduleDetail : psds) {
      if (paymentScheduleDetail.getPaymentDetails() != null) {
        // This schedule detail comes from an edited payment so outstanding amount needs to be
        // properly calculated
        List<FIN_PaymentScheduleDetail> outStandingPSDs = FIN_AddPayment
            .getOutstandingPSDs(paymentScheduleDetail);
        if (outStandingPSDs.size() > 0) {
          outstandingAmount = paymentScheduleDetail.getAmount().add(
              outStandingPSDs.get(0).getAmount());
        } else {
          outstandingAmount = paymentScheduleDetail.getAmount();
        }
      } else {
        outstandingAmount = paymentScheduleDetail.getAmount();
      }
      // Manage negative amounts
      if ((remainingAmount.compareTo(BigDecimal.ZERO) > 0 && remainingAmount
          .compareTo(outstandingAmount) >= 0)
          || ((remainingAmount.compareTo(BigDecimal.ZERO) == -1 && outstandingAmount
              .compareTo(BigDecimal.ZERO) == -1) && (remainingAmount.compareTo(outstandingAmount) <= 0))) {
        recordsAmounts.put(paymentScheduleDetail.getId(), outstandingAmount);
        remainingAmount = remainingAmount.subtract(outstandingAmount);
      } else {
        recordsAmounts.put(paymentScheduleDetail.getId(), remainingAmount);
        remainingAmount = BigDecimal.ZERO;
      }

    }
    return recordsAmounts;
  }

  private List<FIN_PaymentScheduleDetail> getOrderedPaymentScheduleDetails(Set<String> psdSet) {
    OBCriteria<FIN_PaymentScheduleDetail> orderedPSDs = OBDal.getInstance().createCriteria(
        FIN_PaymentScheduleDetail.class);
    orderedPSDs.add(Restrictions.in(FIN_PaymentScheduleDetail.PROPERTY_ID, psdSet));
    orderedPSDs.addOrderBy(FIN_PaymentScheduleDetail.PROPERTY_AMOUNT, true);
    return orderedPSDs.list();
  }

  private List<FIN_PaymentScheduleDetail> filterDocumenttype(
      List<FIN_PaymentScheduleDetail> storedNotSelectedPSDs, String strDocumentType) {
    List<FIN_PaymentScheduleDetail> listIterator = new ArrayList<FIN_PaymentScheduleDetail>(
        storedNotSelectedPSDs);
    for (FIN_PaymentScheduleDetail paymentScheduleDetail : listIterator) {
      if (paymentScheduleDetail.getInvoicePaymentSchedule() != null && "O".equals(strDocumentType)) {
        storedNotSelectedPSDs.remove(paymentScheduleDetail);
      } else if (paymentScheduleDetail.getOrderPaymentSchedule() != null
          && "I".equals(strDocumentType)) {
        storedNotSelectedPSDs.remove(paymentScheduleDetail);
      }
    }
    return storedNotSelectedPSDs;
  }

  private void businessPartnerBlocked(HttpServletResponse response, VariablesSecureApp vars,
      String strBPartnerName) throws IOException, ServletException {

    try {
      JSONObject json = new JSONObject();
      json.put("text", "SelectedBPartnerBlocked");
      response.setContentType("text/html; charset=UTF-8");
      PrintWriter out = response.getWriter();
      out.println("objson = " + json);
      out.close();
    } catch (JSONException e) {
      log4j.error("AddOrderOrInvoiceFurniture - Callback", e);
    }
  }

  public String getServletInfo() {
    return "Servlet that presents the payment proposal";
    // end of getServletInfo() method
  }

}
